package ar.edu.caece.pl.alex.model.impl;

import java.io.IOException;
import java.util.Formatter;

import ar.edu.caece.pl.alex.model.IDictionary;
import ar.edu.caece.pl.alex.model.IToken;

public class Token implements IToken {

	private StringBuilder text = new StringBuilder();
	private int type;
	private boolean retornable = true;
	private int[] coords;
	
	public Token ( int type ) {
		
		this.type = type;
		
		switch (type) {
		//TOKEN_IDENTIFICADOR	=  0; // a-z/A-Z 0-9
		//TOKEN_PALABRA_RESERVADA= 1; // if,then,else...etc
		//TOKEN_NUM_ENTERO		=  2; // 1234
		//TOKEN_NUM_NATURAL		=  3; // 1234n
		//TOKEN_CADENA			=  4; // 'asdf'
		case 4: this.append("'");break;
		//TOKEN_COMENTARIO		=  5; // {asdf}
		case 5: 
			this.append("{");
			this.setRetornable(false);
			break;
		//TOKEN_DOS_PUNTOS		=  6; // :
		case 6: this.append(":");break;
		//TOKEN_ASIGNACION		=  7; // :=
		case 7: this.append(":=");break;
		//TOKEN_OPER_IGUAL		=  8; // =
		case 8: this.append("=");break;
		//TOKEN_OPER_MAS_INT	=  9; // +
		case 9: this.append("+");break;
		//TOKEN_OPER_MAS_NAT	= 10; // ++
		case 10: this.append("++");break;
		//TOKEN_OPER_MENOS_INT	= 11; // -
		case 11: this.append("-");break;
		//TOKEN_OPER_MENOS_NAT	= 12; // --
		case 12: this.append("--");break;
		//TOKEN_OPER_MULT_INT	= 13; // *
		case 13: this.append("*");break;
		//TOKEN_OPER_MULT_NAT	= 14; // **
		case 14: this.append("**");break;
		//TOKEN_OPER_DIV_INT	= 15; // /
		case 15: this.append("/");break;
		//TOKEN_OPER_DIV_NAT	= 16; // //
		case 16: this.append("//");break;
		//TOKEN_OPER_MENOR		= 17; // <
		case 17: this.append("<");break;
		//TOKEN_OPER_MAYOR		= 18; // >
		case 18: this.append(">");break;
		//TOKEN_OPER_MENOR_IGUAL= 19; // <=
		case 19: this.append("<=");break;
		//TOKEN_OPER_MAYOR_IGUAL= 20; // >=
		case 20: this.append(">=");break;
		//TOKEN_OPER_DISTINTO	= 21; // >=
		case 21: this.append("<>");break;
		//TOKEN_PARENTESIS_IZQ	= 22; // (
		case 22: this.append("(");break;
		//TOKEN_PARENTESIS_DER	= 23; // )
		case 23: this.append(")");break;
		//TOKEN_CORCHETE_IZQ	= 24; // [
		case 24: this.append("[");break;
		//TOKEN_CORCHETE_DER	= 25; // ]
		case 25: this.append("]");break;
		//TOKEN_COMA			= 26; // ,
		case 26: this.append(",");break;
		//TOKEN_PUNTO_COMA		= 27; // ;
		case 27: this.append(";");break;
		//TOKEN_SEPARADOR		= 28; // ' '\n\t\r\f\b
		case 28: this.setRetornable(false);break;
		//TOKEN_ERROR			= 29; // caracteres chinos?
		//TOKEN_FIN_DE_ARCHIVO	= 30; // EOF
		case 30: this.append("EOF");break;
		
		}
	}
	
	public Token ( String palabraReservada ) {
		
		IDictionary dic = Dictionary.getInstance();
		
		if (dic.isValid(palabraReservada)) {
			
			this.type = IToken.TYPE_PALABRA_RESERVADA;
			this.append(palabraReservada);
			
		} else {
			throw new IllegalArgumentException("La palabra no se encuentra entre las palabras reservadas.");
		}
	}

	@Override
	public String getTokenText() {
		return this.text.toString();
	}

	@Override
	public int getType() {
		return type;
	}
	
	@Override
	public void setType(int type) {
		this.type = type;
	}
	
	@Override
	public IToken append(String s) throws IllegalStateException {
		this.text.append(s);
		return this;
	}

	@Override
	public boolean isRetornable() {
		return retornable;
	}

	public void setRetornable(boolean retornable) {
		this.retornable = retornable;
	}

	@Override
	public int[] getCoords() {
		return this.coords;
	}

	@Override
	public void setCoords(int[] coords) {
		this.coords = coords;
	}
	
	@Override
	public boolean equals(Object obj) { //No validamos las coordenadas en el equals
		
		//Validaciones genericas
		if (this == obj) {return true;}
		if (obj == null) {return false;}
		if (!(obj instanceof Token)) {return false;}
		
		//Validaciones de negocio
		Token other = (Token) obj;
		if (type != other.type){return false;}
		if (retornable != other.retornable) {return false;}
		if (text == null && other.text != null) {return false;}
		if (type != IToken.TYPE_IDENTIFICADOR &&  //Al identificador no lo podemos validar por su lexema
			type != IToken.TYPE_NUM_NATURAL &&  //Al Numero Natural no lo podemos validar por su lexema
			type != IToken.TYPE_NUM_ENTERO &&  //Al Numero Entero no lo podemos validar por su lexema
			type != IToken.TYPE_CADENA &&  //Al Numero Entero no lo podemos validar por su lexema
			!text.toString().equals(other.text.toString())){return false;} //text es un stringbuilder
		
		//Si no fallo en todas las anteriores...
		return true;
	}


	public String toString() {
		
		StringBuffer sb = new StringBuffer();
		IDictionary dic = Dictionary.getInstance();
		
		sb.append("Token (type:").append(this.getType()).append(" ").
		   append(dic.getTokenDescription(this.getType())).
		   append(")[").append(this.getCoords()[0]).append(",").append(this.getCoords()[1]).append("]: ");
		
		Formatter f = new Formatter();
		f.format("%.50s",sb.toString());
		
		try {
			
			return f.out().append(this.getTokenText()).toString();
			
		} catch (IOException e) {
			
			e.printStackTrace();
			return null;
		}
	}
}
